package com.web.controoller;

import com.web.constant.DataPackageConstants;
import com.web.observers.RequestResponseObserver;
import com.web.pojo.domain.Device;
import com.web.pojo.domain.DeviceWorkParameters;
import com.web.pojo.domain.UserInfo;
import com.web.pojo.vo.AuthorizeDTO;
import com.web.pojo.vo.CommonResult;
import com.web.service.DeviceServer;
import com.web.service.NetworkServer;
import com.web.service.UserServer;
import com.web.utils.DownLinkDataUtil;
import com.web.utils.SecurityUtils;
import com.web.utils.ToolUtil;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

@CrossOrigin
@RequestMapping("/device")
@RestController
public class DeviceController {

    @Autowired
    DeviceServer deviceServer;

    @Autowired
    NetworkServer networkServer;

    @Autowired
    UserServer userServer;

//    @PostMapping("/device")
//    @ApiOperation("添加设备信息")
//    public Callable<CommonResult> insertDeviced(@RequestBody Device deviceDO) throws InterruptedException {
//
//        byte[] DeviceEui = DownLinkDataUtil.toByteArray(deviceDO.getDeviceEui());
//
//        byte[] outToken =DownLinkDataUtil.CalAppNonce(2);
//
//        byte[] down = DownLinkDataUtil.gatewayRegister(outToken, REGISTER, DeviceEui);
//
//        Global.getOutQueue().put(down);
//        MyCallable calla = new MyCallable();
//        Callable<CommonResult> callable = new Callable<CommonResult>() {
//            @Override
//            public CommonResult call() throws Exception {
//                for (;;) {
//                    byte[] take = Global.getInQueue().take();
//                    byte[] inToken = Arrays.copyOfRange(take, 1, 3);
//                    System.out.println(inToken);
//                    if (Arrays.equals(inToken, outToken)) {
//                        deviceServer.insertDevice(deviceDO);
//                        return new CommonResult(200, "okk");
//                    }
//                }
//
//            }
//        };
//
//        return calla;
//    }


    @ResponseBody
    @GetMapping("/device/{dev_eui}")
    @ApiOperation("得到设备信息")
    public Device getDevice(@PathVariable("dev_eui") String dev_eui) {
        return deviceServer.getDevice(dev_eui);
    }

    @PostMapping("/insert")
    @ApiOperation("添加设备信息")
    public CommonResult insertDevice(@RequestBody Device device) throws InterruptedException {

        if (!deviceServer.checkDeviceEuiUnique(device.getDeviceEui())) {
            return CommonResult.fail("设备EUI:'" + device.getDeviceEui() + "'已被注册");
        }

        if (!ToolUtil.checkIsHexadecimal(device.getDeviceEui()) || device.getDeviceEui().length() != 16) {
            return CommonResult.error("该设备EUI格式错误");
        }

        if (!ToolUtil.checkIsHexadecimal(device.getDeviceEui()) || device.getDeviceEui().length() != 16) {
            return CommonResult.error("该设备EUI格式错误");
        }

        if (!ToolUtil.checkIsHexadecimal(device.getDeviceAppkey()) || device.getDeviceAppkey().length() != 32) {
            return CommonResult.error("该设备APPKEY格式错误");
        }

        if (device.getDeviceAddr() == null || "".equals(device.getDeviceAddr())) {
            String deviceAddr;
            do {
                deviceAddr = Integer.toHexString(ToolUtil.generateAddr()).toUpperCase();
            } while (!deviceServer.checkDeviceAddrUnique(deviceAddr));
            device.setDeviceAddr(deviceAddr);
        } else {
            if (!ToolUtil.checkIsHexadecimal(device.getDeviceAddr()) || device.getDeviceAddr().length() != 8) {
                return CommonResult.error("该网关ADDR格式错误");
            }
        }

        byte[] deviceEuiBytes = ToolUtil.toByteArray(device.getDeviceEui());
        byte[] deviceAddrBytes = ToolUtil.toByteArray(device.getDeviceAddr());
        byte[] token = ToolUtil.CalAppNonce(2);
        byte[] down = DownLinkDataUtil.deviceRegister(token, DataPackageConstants.REGISTER, deviceEuiBytes, deviceAddrBytes);
        RequestResponseObserver gatewayResponse = new RequestResponseObserver(token);
        CompletableFuture<Boolean> isDown = networkServer.downstreamData(down);
        CompletableFuture<Boolean> isResponse = networkServer.checkGateWayResponse(gatewayResponse);

        try {
            isDown.get(5, TimeUnit.SECONDS);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            CommonResult.error("插入错误，下位机未连接");
        }
        try {
            isResponse.get(5, TimeUnit.SECONDS);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            CommonResult.error("插入错误，下位机未回应");
        }

        device.setDeviceAddr(device.getDeviceAddr().toUpperCase());
        device.setDeviceAppkey(device.getDeviceAppkey().toUpperCase());
        return CommonResult.insert(deviceServer.insertDevice(device));

    }

    @PostMapping("/update")
    @ApiOperation("修改设备信息")
    public CommonResult updateDevice(@RequestBody Device device) {
        device.setUpdateBy(SecurityUtils.getUsername());
        return CommonResult.update(deviceServer.updateDevice(device));
    }

    @PostMapping("/delete")
    @ApiOperation("删除设备信息列表")
    public CommonResult deleteDevice(@RequestBody List<Integer> deviceIds) {
        String updateBy = SecurityUtils.getUsername();
        return CommonResult.delete(deviceServer.deleteDevice(updateBy, deviceIds));
    }

    @PostMapping("/details")
    @ApiOperation("查看设备详细信息")
    public CommonResult deviceDetails(@RequestBody Integer deviceId) {
        Device device = deviceServer.selectDeviceDetails(deviceId);
        return CommonResult.select(device);
    }

    @PostMapping("/deviceList")
    @ApiOperation("查看设备信息列表")
    public CommonResult deviceList(@RequestBody(required = false) String str) {
        Integer userId = SecurityUtils.getUserId();
        List<Device> list = deviceServer.selectDeviceList(userId, str);
        return CommonResult.select(list);
    }

    @PostMapping("/checkDeviceEuiUnique")
    @ApiOperation("检查设备eui是否正确")
    public CommonResult checkDeviceEuiUnique(@RequestBody(required = false) String deviceEui) {
        if (deviceEui == null) {
            return CommonResult.error("请输入设备EUI");
        }
        if (!ToolUtil.checkIsHexadecimal(deviceEui) || deviceEui.length() != 16) {
            return CommonResult.error("该设备EUI格式错误");
        }
        if (!deviceServer.checkDeviceEuiUnique(deviceEui)) {
            return CommonResult.fail("该设备EUI已被注册");
        }
        return CommonResult.success("该设备Eui可以注册");
    }

    @PostMapping("/selectDeviceByAddressId")
    @ApiOperation("根据地址查询设备 ")
    public CommonResult selectDeviceByAddressId(@RequestBody Integer addressId) {
        Integer userId = SecurityUtils.getUserId();
        List<Device> list = deviceServer.selectDeviceListByAddressId(userId, addressId);
        return CommonResult.select(list);
    }


    @PostMapping("/workParameters")
    @ApiOperation("查看设备工作参数接口")
    public CommonResult selectDeviceWorkParameters(@RequestBody Integer deviceId) {
        DeviceWorkParameters deviceWorkParameters = deviceServer.selectDeviceWorkParameters(deviceId);
        return CommonResult.select(deviceWorkParameters);
    }

    @PostMapping("/authorize")
    @ApiOperation("授权")
    private CommonResult authorizeDevice(@RequestBody AuthorizeDTO dto) {
        UserInfo userInfo = userServer.selectUserInfoByUsername(dto.getUsername());
        if (userInfo == null) {
            return CommonResult.error("用户不存在");
        }
        deviceServer.authorizeDevice(dto.getIds(), userInfo.getUserId());
        return CommonResult.success("授权成功");
    }

}
